using System;
using System.Reflection;
using System.Text;
using System.Collections;
using System.Xml;
using System.Diagnostics;

using System.Runtime.InteropServices;
using System.Diagnostics.SymbolStore;

using Pdb.Model;

namespace Pdb.Tools
{
	public class PdbWriter
	{
		public PdbWriter(string assemblyName)
		{
			_assemblyName = assemblyName;
			_pdbName = CreatePdbFromAssembly(_assemblyName);
		}

		private string tmpPdb;
		public string TmpPdb
		{
			get
			{
				return tmpPdb;
			}
			set
			{
				tmpPdb = value;
			}
		}

		private string _pdbName;
		public string PdbName
		{
			get
			{
				return _pdbName;
			}
			set
			{
				_pdbName = value;
			}
		}

		private string _assemblyName;
		public string AssemblyName
		{
			get
			{
				return _assemblyName;
			}
			set
			{
				_assemblyName = value;
			}
		}

		private string CreatePdbFromAssembly(string assemblyName)
		{
			string noExt = assemblyName.Substring(0, assemblyName.LastIndexOf('.'));
			
			return String.Concat(noExt, ".pdb");
		}

		private string CreateTmpPdbFromAssembly(string assemblyName)
		{
			string name = assemblyName.Substring(assemblyName.LastIndexOf('\\') + 1, assemblyName.LastIndexOf('.') - assemblyName.LastIndexOf('\\') - 1);
			string path = assemblyName.Substring(0, assemblyName.LastIndexOf('\\') + 1);

			return String.Concat(path, "$", name, ".pdb");
		}

		public void Write(PdbInfos pdb)
		{
			tmpPdb = CreateTmpPdbFromAssembly(_assemblyName);

			ISymbolWriter w = SymUtil.GetSymbolWriterForFile(_assemblyName, tmpPdb);

			Hashtable docWriters = new Hashtable();
			foreach (File file in pdb.Files)
			{
				ISymbolDocumentWriter writer = w.DefineDocument(file.Name, file.Language, file.LanguageVendor, file.DocumentType);
				docWriters.Add(file.Id, writer);
			}

			foreach (Method m in pdb.Methods)
			{
				SymbolToken parent = new SymbolToken(m.Token);

				int[] offsets = new int[m.SequencePoints.Count];
				int[] startRows = new int[m.SequencePoints.Count];
				int[] endRows = new int[m.SequencePoints.Count];
				int[] startColumns = new int[m.SequencePoints.Count];
				int[] endColumns = new int[m.SequencePoints.Count];
				int[] files = new int[m.SequencePoints.Count];

				for(int i = 0; i < m.SequencePoints.Count; i++)
				{
					Entry e = m.SequencePoints[i];

					offsets[i] = e.Offset;
					startRows[i] = e.StartRow;
					endRows[i] = e.EndRow;
					startColumns[i] = e.StartColumn;
					endColumns[i] = e.EndColumn;
					files[i] = e.FileId;
				}

				w.OpenMethod(parent);

				w.OpenScope(m.StartScope);

				w.UsingNamespace(m.Namespace);

				w.OpenNamespace(m.Namespace);

				w.DefineSequencePoints((SymDocumentWriter)docWriters[files[0]], offsets, startRows, startColumns, endRows, endColumns);

				w.CloseNamespace();

				w.CloseScope(m.EndScope);

				w.CloseMethod();
			}
			//w.Close();

			((SymWriter)w).Close();
			//((SymWriter)w).__dtor();

//			if(System.IO.File.Exists(_pdbName))
//				System.IO.File.Delete(_pdbName);
//
			if(System.IO.File.Exists(tmpPdb))
				System.IO.File.Copy(tmpPdb, _pdbName, true);
//
			if(System.IO.File.Exists(tmpPdb))
				System.IO.File.Delete(tmpPdb);

			PdbCheck.Check(_assemblyName, _pdbName);
		}
	}
}
